#ifndef SIGN_TRACKER_HPP_
#define SIGN_TRACKER_HPP_

#include "utility.hpp"
#include "cf_libs/dsst/dsst_tracker.hpp"


using namespace cf_tracking;
using namespace LfUtils;
class Sign_Tracker : public DsstTracker {

public:
    std::array<cv::Point2f,4> refined_vertices;


public:
    Sign_Tracker(bool is_debug_msg = false) : DsstTracker(kDsst_param_), is_debug_msg_(is_debug_msg) {
        tracked_frames_ = 0;
        losted_frames_ = 0;
        status_ = Active;
        id_ = set_id();
    }

    ~Sign_Tracker() {}

    bool is_active()   const { return (status_ == Active); }
    bool is_tracked()  const { return (status_ == Tracked); }
    bool is_lost()     const { return (status_ == Lost); }
    bool is_inactive() const { return (status_ == Inactive); }

    template<typename T>
    float get_IOU(const cv::Rect_<T> &detection) {
        return cal_IOU(detection, get_lastBoundingBox());
    }

    template<typename T>
    float get_OLR(const cv::Rect_<T> &detection) {
        auto AND_rect = detection & get_lastBoundingBox();
        float overlap_ratio = AND_rect.area() / detection.area();
        return overlap_ratio;
    }

    template<typename T>
    void init(const cv::Mat &img, cv::Rect_<T> &bbox) {
        bbox_ = bbox;
        reinit(img, bbox_);
        if (is_debug_msg_) { debug_msg(); }
    }

    float detectAt(const cv::Mat &img, cv::Rect2f bbox) {
            return detectAt_(img, bbox);
    }

    void lose_tracker() {
        tracked_frames_ = 0;
        status_ = Lost;
        losted_frames_++;
        if (losted_frames_ >= LOST_TOLERANCE) {
            status_ = Inactive;
        }
        if (is_debug_msg_) { debug_msg(); }
    }

    bool update_tracker(const cv::Mat &img, cv::Rect2f bbox) {
        bbox_ = bbox;
        bool track_sucess = updateAt(img, bbox_);

        if (track_sucess) {
            losted_frames_ = 0;
            tracked_frames_++;
            status_ = Tracked;
            if (is_debug_msg_) { debug_msg(); }
        }
        return track_sucess;
    }

    size_t get_id() const {
        return id_;
    }

    const cv::Rect2f get_bbox() const {
        return bbox_;
    }


    void debug_msg() {
        switch (status_) {
            case Active: {
                std::cout << "Creat Tracker_" << std::to_string(id_) << std::endl;
                break;
            }
            case Tracked: {
                std::cout << "Update Tracker_" << std::to_string(id_) << std::endl;
                break;
            }
            case Inactive: {
                std::cout << "Lost Tracker_" << std::to_string(id_) << std::endl;
                break;
            }
            default: {
                std::cout << "Invalid State_" << std::to_string(id_) << std::endl;
                break;
            }
        }

        std::cout << "===== Tracker_" << std::to_string(id_) << " =====" << std::endl
                  << "  status: " << status_str() << std::endl;
        if (is_tracked()) {
            std::cout << "  psrClamped: " << get_psrClamped() << std::endl;
        }

        std::cout << "  tracked_frames: " << tracked_frames_ << std::endl
                  << "  losted_frames: " << losted_frames_ << std::endl
                  << "====================" << std::endl << std::endl;
    }

    std::string info() {
        std::stringstream ss;
        ss << "[" << std::to_string(id_) << "]: tracked_frames = " << tracked_frames_ << ", psr = " << fixed_precision(std::to_string(_psrClamped), 2);
        return ss.str();
    }

    void draw_result(cv::Mat &debug_img, cv::Scalar color = YELLOW) {
        std::string ID = "["+std::to_string(id_)+"]";
        cv::Point2f shift(0, -10);
        cv::putText(debug_img, ID, bbox_.tl()+shift, cv::FONT_HERSHEY_COMPLEX, 0.8, color,2);
        if (is_active())  { cv::rectangle(debug_img, bbox_, BLUE, 2); }
        if (is_tracked()) { cv::rectangle(debug_img, bbox_, GREEN, 2); }
        if (is_lost())    { draw_crossedRect(debug_img, bbox_, RED, 2); }
    }

private:
    std::string status_str() {
        std::string msg;
        if (status_ == Active)   { msg = "Active"; }
        if (status_ == Tracked)  { msg = "Tracked"; }
        if (status_ == Lost)     { msg = "Lost"; }
        if (status_ == Inactive) { msg = "Inactive"; }
        return msg;
    }

    size_t set_id() {
        static size_t _ID_counter = 1;
        return _ID_counter++;
    }

private:
    static const DsstParameters kDsst_param_;

    enum STATUS {
        Active,
        Tracked,
        Lost,
        Inactive
    };

    enum CRITERIA {
        LOST_TOLERANCE = 1,
    };

    size_t id_;
    STATUS status_;
    size_t tracked_frames_;
    size_t losted_frames_;
    cv::Rect2f bbox_;
    bool is_debug_msg_;
};


#endif // SIGN_TRACKER_HPP_